/* Copyright (c) 2022-2025 Qualcomm Technologies International, Ltd. */
/* %%version */

#include "csr_synergy.h"

#ifndef EXCLUDE_GATT_XPAN_CLIENT_MODULE

#include "gatt_xpan_client_debug.h"
#include "gatt_xpan_client_private.h"
#include "gatt_xpan_client_common.h"
#include "gatt_lib.h"

static void xpanFreeContainedPointersWiFiScanResults(uint8 numBssids, XpanClientApScanResult** apScanResult)
{
    unsigned int i;
    numBssids = MIN(numBssids, XPAN_CLIENT_WIFI_SCAN_RESULT_NUM_APS_MAX);

    for (i = 0; i < numBssids; i++)
    {
        if (apScanResult[i])
        {
            if (apScanResult[i]->ssid)
            {
                pfree(apScanResult[i]->ssid);
                apScanResult[i]->ssid = NULL;
            }
            pfree(apScanResult[i]);
            apScanResult[i] = NULL;
        }
    }
}

void xpanFreeContainedPointersWiFiScanResultsReq(XpanClientInternalMsgWiFiScanResultsReq* msg)
{
    xpanFreeContainedPointersWiFiScanResults(msg->numBssids, &msg->apScanResult[0]);
}

void xpanFreeContainedPointersWiFiScanResultsOp(GattXpanClientWiFiScanResultsOp* op)
{
    xpanFreeContainedPointersWiFiScanResults(op->numBssids, &op->apScanResult[0]);
}

/****************************************************************************/
void xpanClientBufferWithLengthDecode(GattXpanClientBufferWithLength* buff,
                                             const uint8** pdataPtr,
                                             const uint8* const lastPtr)
{
    if (*pdataPtr <= (lastPtr - sizeof(uint8)))
    {
        buff->length = **pdataPtr;
        *pdataPtr += 1;
    }

    if (*pdataPtr <= (lastPtr - buff->length))
    {
        buff->value = CsrPmemAlloc(buff->length * sizeof(uint8));
        SynMemCpyS(buff->value,
                   buff->length,
                   *pdataPtr,
                   lastPtr - *pdataPtr);
        *pdataPtr += buff->length;
    }
}

void xpanClientBufferFixedLengthDecode(uint8* buffer,
                                       uint8 length,
                                       const uint8** pdataPtr,
                                       const uint8* const lastPtr)
{
    /* Store the data (pointed to by pdataPtr) into 'buffer' */
    if (*pdataPtr  <= (lastPtr - length))
    {
        SynMemCpyS(buffer,
                   length,
                   *pdataPtr,
                   lastPtr - *pdataPtr);
    }
    *pdataPtr += length;
}

/***********************************************************************************************************************/
void xpanClientDecodeStoredSsid(GattXpanClientStoredSsid* storedSsid, uint16 sizeValue, const uint8 *value)
{
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + sizeValue;

    uint8 ssidIndex;

    storedSsid->numSsids = *dataPtr++;

    /* It's not usually a good thing to trust values received over the wire, but this is the Client
     * which is (at the moment) for test purposes only */
    storedSsid->ssids = CsrPmemAlloc(storedSsid->numSsids * sizeof(GattXpanClientBufferWithLength));

    for (ssidIndex = 0; ssidIndex < storedSsid->numSsids; ++ssidIndex)
    {
        xpanClientBufferWithLengthDecode(&storedSsid->ssids[ssidIndex],
                                         &dataPtr,
                                         lastPtr);
    }
}

void xpanClientDecodeIpAddressData(GattXpanClientIpAddressData* const ipAddressData,
                                   uint16 size_value,
                                   const uint8 *value,
                                   uint8 ipAddressLen)
{
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + size_value;
    uint8 ssidIndex;
    uint8 ipIndex;

    ipAddressData->numSsids = *dataPtr++;
    /* It's not usually a good thing to trust values received over the wire, but this is the Client
     * which is (at the moment) for test purposes only */
    ipAddressData->ssidData = CsrPmemAlloc(ipAddressData->numSsids * sizeof(GattXpanClientIpAddressSsidData));

    for (ssidIndex = 0; ssidIndex < ipAddressData->numSsids; ++ssidIndex)
    {
        /* Store the SSID  */
        xpanClientBufferWithLengthDecode(&ipAddressData->ssidData[ssidIndex].ssid,
                                         &dataPtr,
                                         lastPtr);
        /* Store the BSSID */
        xpanClientBufferFixedLengthDecode(&ipAddressData->ssidData[ssidIndex].bssid[0],
                                          XPAN_CLIENT_BSSID_LENGTH_OCTETS,
                                          &dataPtr,
                                          lastPtr);

        /* Store the number of IP Addresses */
        if (dataPtr <= (lastPtr - sizeof(uint8)))
            ipAddressData->ssidData[ssidIndex].numIpAddresses = *dataPtr++;

        /* Store the IP Address values */
        ipAddressData->ssidData[ssidIndex].ipAddresses = CsrPmemAlloc(ipAddressData->ssidData[ssidIndex].numIpAddresses * sizeof(GattXpanClientIpAddress));
        for (ipIndex = 0; ipIndex < ipAddressData->ssidData[ssidIndex].numIpAddresses; ++ipIndex)
        {
            if (dataPtr <= (lastPtr - sizeof(uint8)))
                ipAddressData->ssidData[ssidIndex].ipAddresses[ipIndex].status = *dataPtr++;

            if (dataPtr <= (lastPtr - ipAddressLen))
            {
                ipAddressData->ssidData[ssidIndex].ipAddresses[ipIndex].ipAddress.length = ipAddressLen;
                ipAddressData->ssidData[ssidIndex].ipAddresses[ipIndex].ipAddress.value = CsrPmemAlloc(ipAddressLen);

                xpanClientBufferFixedLengthDecode(ipAddressData->ssidData[ssidIndex].ipAddresses[ipIndex].ipAddress.value,
                                                  ipAddressLen,
                                                  &dataPtr,
                                                  lastPtr);
            }


            xpanClientBufferFixedLengthDecode(ipAddressData->ssidData[ssidIndex].ipAddresses[ipIndex].audioLocation,
                                              XPAN_CLIENT_AUDIO_LOC_LENGTH_OCTETS,
                                              &dataPtr,
                                              lastPtr);

            if (dataPtr <= (lastPtr - sizeof(uint8)))
                ipAddressData->ssidData[ssidIndex].ipAddresses[ipIndex].role = *dataPtr++;

            xpanClientBufferFixedLengthDecode(ipAddressData->ssidData[ssidIndex].ipAddresses[ipIndex].macAddress,
                                              XPAN_CLIENT_MAC_ADDRESS_LEN,
                                              &dataPtr,
                                              lastPtr);
        }
    }
}

/***********************************************************************************************************************/
void xpanClientDecodeL2capTcpPort(GattXpanClientL2capTcpPort* l2capTcpPort, uint16 size_value, const uint8 *value)
{
    if (size_value >= 2)
    {
        *l2capTcpPort  = value[0];
        *l2capTcpPort |= value[1] << 8;
    }
}

/***********************************************************************************************************************/
void xpanClientDecodeUdpPort(GattXpanClientUdpPort* udpPort, uint16 size_value, const uint8 *value)
{
    if (size_value >= 2)
    {
        *udpPort  = value[0];
        *udpPort |= value[1] << 8;
    }
}

/***********************************************************************************************************************/
void xpanClientRoamingRequestResponse(GattXpanClientStatus* status, uint16 size_value, const uint8 *value)
{
    /*! Store the Roaming Request Response value:
                                0x00 = Request accepted
                                0x01 = Request rejected
     */
    if (0 < size_value)
        *status = value[0];
}


/***********************************************************************************************************************/
void xpanClientDecodeClearToSend(GattXpanClientClearToSend* clearToSend, uint16 size_value, const uint8 *value)
{
    /*! Store the Clear to Send value:
                                0x00 = Not ready to accept audio data over XPAN
                                0x01 = Ready to accept audio data over XPAN
     */
    if (0 < size_value)
        *clearToSend = value[0];
}

/***********************************************************************************************************************/
void xpanClientDecodeBearerPreference(GattXpanClientBearerPreference* bearerPreference, uint16 size_value, const uint8 *value)
{
    if (0 < size_value)
        *bearerPreference = value[0];
}

/***********************************************************************************************************************/
void xpanClientDecodeMacAddresses(GattXpanClientMacAddresses* macAddresses, uint16 size_value, const uint8 *value)
{
    uint8 elemIndex;
    uint8 macIndex;
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + size_value;

    /*
        Num MAC Addresses      1 Octet         Number of MAC Addresses
        MAC Address[i]         6 Octets        MAC address
        Audio Location[i]      4 Octets        Audio Location associated with MAC Address[i]
    */
    if (dataPtr <= (lastPtr - sizeof(uint8)))
        macAddresses->numMacAddresses = *dataPtr++;

    /* Store the number of MAC Address/Audio Location data sets */
    macAddresses->macAddressAudioLocationInfo = CsrPmemAlloc(macAddresses->numMacAddresses * sizeof(GattXpanClientMacAddressAudioLocationInfo));
    for (macIndex = 0; macIndex < macAddresses->numMacAddresses; ++macIndex)
    {
        /* Store the 6 octet MAC address for this index value */
        if (dataPtr <= (lastPtr - XPAN_CLIENT_MAC_ADDRESS_LEN))
        {
            for (elemIndex = 0; elemIndex < XPAN_CLIENT_MAC_ADDRESS_LEN; ++elemIndex)
            {
                macAddresses->macAddressAudioLocationInfo[macIndex].macAddress[elemIndex] = *dataPtr++;
            }
        }
        /* Store the 32 bit audio location for this index value */
        if (dataPtr  <= (lastPtr - sizeof(uint32)))
        {
            macAddresses->macAddressAudioLocationInfo[macIndex].audioLocation = *dataPtr++;
            macAddresses->macAddressAudioLocationInfo[macIndex].audioLocation |= *dataPtr++ << 8;
            macAddresses->macAddressAudioLocationInfo[macIndex].audioLocation |= *dataPtr++ << 16;
            macAddresses->macAddressAudioLocationInfo[macIndex].audioLocation |= *dataPtr++ << 24;
        }
    }
}

/***********************************************************************************************************************/
void xpanClientDecodeRequestedSapPowerState(GattXpanClientSapPowerStateData* sapPowerStateData, uint16 size_value, const uint8 *value)
{
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + size_value;

/*
    State       1 Octet     0x00: Deep sleep
                            0x01: Active
 */
    if (dataPtr <= (lastPtr - sizeof(uint8)))
        sapPowerStateData->state = *dataPtr++;

    /* no longer in the QBCESPEC (last checked on 22/09/2022)
    if (dataPtr <= (lastPtr - sizeof(uint8)))
        sapPowerStateData->requester = *dataPtr++;
    */

}

/***********************************************************************************************************************/
void xpanClientDecodeServerFeatures(GattXpanClientServerFeatures* serverFeatures, uint16 size_value, const uint8 *value)
{
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + size_value;

    xpanClientBufferFixedLengthDecode(serverFeatures->value,
                                      XPAN_CLIENT_SERVER_FEATURES_LEN,
                                      &dataPtr,
                                      lastPtr);
}

/***********************************************************************************************************************/
void xpanClientDecodeAudioBearerSwitchResponse(AudioBearerSwitchResponse* audioBearerSwitchResponse, uint16 size_value, const uint8 *value)
{
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + size_value;

/*
    Audio Bearer Switch Response       1 Octet      0x00: READY_TO_PERFORM_AUDIO_BEARER_SWITCH
                                                    0x01: FAILURE_TO_PERFORM_AUDIO_BEARER_SWITCH
 */
    if (dataPtr <= (lastPtr - sizeof(uint8)))
        *audioBearerSwitchResponse = *dataPtr++;

}

/***********************************************************************************************************************/
void xpanClientDecodeNumDevicesPresent(NumDevicesPresent* numDevices, uint16 size_value, const uint8 *value)
{
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + size_value;

/*
    Num Devices                         1 Octet      0x01-0xFF: Number of devices present
 */
    if (dataPtr <= (lastPtr - sizeof(uint8)))
        *numDevices = *dataPtr++;
}

/***********************************************************************************************************************/
void xpanClientDecodeVoiceBackChannelPeriodicity(VoiceBackChannelPeriodicity* periodicity, uint16 size_value, const uint8 *value)
{
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + size_value;

/*
    Periodicity                         1 Octet      0x01-0xFF:  Periodicity of voice back channel packets, in milliseconds
 */
    if (dataPtr <= (lastPtr - sizeof(uint8)))
        *periodicity = *dataPtr++;
}

/***********************************************************************************************************************/
void xpanClientDecodeTwtConfiguration(GattXpanClientTwtConfiguration* twtConfiguration, uint16 size_value, const uint8 *value)
{
    const uint8* dataPtr = value;
    const uint8* lastPtr = value + size_value;

/*
    Setup ID                          1 Octet             Unique ID representing a TWT session. Nonzero integer.
    Negotiation Type                  1 Bit               0 = Individual TWT
                                                          1 = Broadcast TWT
    Flow Type                         1 Bit               0 = Announced
                                                          1 = Unannounced
    Trigger Type                      1 Bit               0 = NonTrigger enabled
                                                          1 = Trigger enabled
    RFU                               5 Bits              Reserved for future use
    Desired Wake Duration             4 Octets            Value in microseconds. May be set to the same value as the
                                                          Desired Wake Interval field if early termination is used.
    Desired Wake Interval             4 Octets            Value in microseconds. This field shall be set to a valid value.
    Desired Wake TSF Primary          8 Octets            Time, in microseconds, when the first TWT starts for the
                                                          Primary earbud with reference to the TSF. Set to 0 to indicate
                                                          that it is not valid in which case the time when the first
                                                          TWT starts is retrieved from the WiFi subsystem.
    Desired Wake TSF Secondary Offset 4 Octets            Offset, in microseconds, from Desired Wake TSF Primary when
                                                          the TWT starts for the Secondary earbud. This field shall be
                                                          set to a valid value.
*/
    /* Store the SetupId */
    if (dataPtr <= (lastPtr - sizeof(uint8)))
        twtConfiguration->setupId = *dataPtr++;

    /* Store the Flags */
    if (dataPtr <= (lastPtr - sizeof(uint8)))
        twtConfiguration->flags = *dataPtr++;

    if (dataPtr <= (lastPtr - sizeof(twtConfiguration->desiredWakeDuration)))
    {
        twtConfiguration->desiredWakeDuration  = *dataPtr++;
        twtConfiguration->desiredWakeDuration |= *dataPtr++ << 8;
        twtConfiguration->desiredWakeDuration |= *dataPtr++ << 16;
        twtConfiguration->desiredWakeDuration |= *dataPtr++ << 24;
    }

    if (dataPtr <= (lastPtr - sizeof(twtConfiguration->desiredWakeInterval)))
    {
        twtConfiguration->desiredWakeInterval  = *dataPtr++;
        twtConfiguration->desiredWakeInterval |= *dataPtr++ << 8;
        twtConfiguration->desiredWakeInterval |= *dataPtr++ << 16;
        twtConfiguration->desiredWakeInterval |= *dataPtr++ << 24;
    }

    xpanClientBufferFixedLengthDecode(&twtConfiguration->desiredWakeTsfLeft[0],
                                      GATT_XPAN_CLIENT_READ_TWT_CONFIG_TSF_LEFT_LEN,
                                      &dataPtr,
                                      lastPtr);

    if (dataPtr <= (lastPtr - sizeof(twtConfiguration->desiredWakeTsfRightOffset)))
    {
        twtConfiguration->desiredWakeTsfRightOffset  = *dataPtr++;
        twtConfiguration->desiredWakeTsfRightOffset |= *dataPtr++ << 8;
        twtConfiguration->desiredWakeTsfRightOffset |= *dataPtr++ << 16;
        twtConfiguration->desiredWakeTsfRightOffset |= *dataPtr++ << 24;
    }
}

/***********************************************************************************************************************/
void xpanClientDecodeConnectedDevices(GattXpanClientConnectedDevices* connectedDevices, uint16 size_value, const uint8 *value)
{
    uint16 valueIndex = 0;
    uint8 transIndex;
    /*
      Num Devices       1 Octet     Number of connected devices
      Transport[i]      1 Octet     0x00 = Bluetooth TWM
                                    0x01 = Bluetooth LE Audio
                                    0x02 = XPAN non2.4G P2P
                                    0x03 = XPAN 2.4G P2P
                                    0x04 = XPAN non2.4G AP
                                    0x05 = XPAN 2.4G AP
                                    Others = Reserved
      Center Frequency  2 Octets    Center frequency (in MHz; whole number only). Only valid if Transport[i] is 0x02 or 0x03.

    */
    /* Store the Num Devices */
    if (valueIndex < size_value)
        connectedDevices->numDevices = value[valueIndex++];

    /* Store the number of Transports and corresponding centre frequencies */
    connectedDevices->transportDescr = CsrPmemAlloc(connectedDevices->numDevices * sizeof(GattXpanClientTransportDescriptor));
    for (transIndex = 0; transIndex < connectedDevices->numDevices; ++transIndex)
    {
        if (valueIndex < size_value)
            connectedDevices->transportDescr[transIndex].transport = value[valueIndex++];

        if (valueIndex  <= (size_value - sizeof(uint16)))
        {
            connectedDevices->transportDescr[transIndex].primaryFrequencyMhz = value[valueIndex++];
            connectedDevices->transportDescr[transIndex].primaryFrequencyMhz |= value[valueIndex++] << 8;
        }
    }

}

/***********************************************************************************************************************/
bool xpanClientGetHandle(GXPANC *const gattXpanClient, XpanClientCharacteristicId charId, uint16* handle, XpanClientCharType readType)
{
    bool handleInitialised = TRUE;

    if (readType == XPAN_CLIENT_CHAR_TYPE_CHARACTERISTIC_CLIENT_CONFIG)
    {
        switch (charId)
        {
        case GATT_XPAN_CLIENT_STORED_SSID:
            {
                *handle = gattXpanClient->handles.storedSsidCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_IPV4_ADDRESS:
            {
                *handle = gattXpanClient->handles.Ipv4AddressCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_IPV6_ADDRESS:
            {
                *handle = gattXpanClient->handles.Ipv6AddressCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_L2CAP_TCP_PORT:
            {
                *handle = gattXpanClient->handles.L2capTcpPortCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_UDP_PORT:
            {
                *handle = gattXpanClient->handles.UdpPortCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_CONNECTED_DEVICES:
            {
                *handle = gattXpanClient->handles.ConnectedDevicesCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_CLEAR_TO_SEND:
            {
                *handle = gattXpanClient->handles.ClearToSendCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_BEARER_PREFERENCE_ADDRESS:
            {
                *handle = gattXpanClient->handles.BearerPreferenceCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_MAC_ADDRESS:
            {
                *handle = gattXpanClient->handles.MacAddressCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_REQUESTED_SAP_POWER_STATE:
            {
                *handle = gattXpanClient->handles.RequestedSapPowerStateCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_SERVER_FEATURES:
            {
                *handle = gattXpanClient->handles.serverFeaturesCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_AUDIO_BEARER_SWITCH_RESPONSE:
            {
                *handle = gattXpanClient->handles.audioBearerSwitchResponseCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_NUM_DEVICES_PRESENT:
            {
                *handle = gattXpanClient->handles.numDevicesPresentCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_VOICE_BACK_CHANNEL_PERIODICITY:
            {
                *handle = gattXpanClient->handles.voiceBackChannelPeriodicityCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_REQUEST_WIFI_SCAN_RESULTS:
            {
                *handle = gattXpanClient->handles.requestWiFiScanResultsCccHandle;
            }
            break;
        case GATT_XPAN_CLIENT_ROAMING_REQUEST_RESPONSE:
            {
                *handle = gattXpanClient->handles.roamingRequestResponseCccHandle;
            }
            break;
        default:
            {
                handleInitialised = FALSE;
                GATT_XPAN_CLIENT_WARNING("Invalid XPAN Characteristic Id\n");
            }
            break;
        }
    }
    else if (readType == XPAN_CLIENT_CHAR_TYPE_CHARACTERISTIC)
    {
        switch (charId)
        {
        case GATT_XPAN_CLIENT_STORED_SSID:
            {
                *handle = gattXpanClient->handles.storedSsidHandle;
            }
            break;
        case GATT_XPAN_CLIENT_IPV4_ADDRESS:
            {
                *handle = gattXpanClient->handles.Ipv4AddressHandle;
            }
            break;
        case GATT_XPAN_CLIENT_IPV6_ADDRESS:
            {
                *handle = gattXpanClient->handles.Ipv6AddressHandle;
            }
            break;
        case GATT_XPAN_CLIENT_L2CAP_TCP_PORT:
            {
                *handle = gattXpanClient->handles.L2capTcpPortHandle;
            }
            break;
        case GATT_XPAN_CLIENT_UDP_PORT:
            {
                *handle = gattXpanClient->handles.UdpPortHandle;
            }
            break;
        case GATT_XPAN_CLIENT_MDNS_SRV_UUID:
            {
                *handle = gattXpanClient->handles.MDnsSrvUuidHandle;
            }
            break;
        case GATT_XPAN_CLIENT_TWT_CONFIGURATION:
            {
                *handle = gattXpanClient->handles.TwtConfigurationHandle;
            }
            break;
        case GATT_XPAN_CLIENT_CONNECTED_DEVICES:
            {
                *handle = gattXpanClient->handles.ConnectedDevicesHandle;
            }
            break;
        case GATT_XPAN_CLIENT_CLEAR_TO_SEND:
            {
                *handle = gattXpanClient->handles.ClearToSendHandle;
            }
            break;
        case GATT_XPAN_CLIENT_XPAN_CONTROL_POINT:
            {
                *handle = gattXpanClient->handles.controlPointHandle;
            }
            break;
        case GATT_XPAN_CLIENT_BEARER_PREFERENCE_ADDRESS:
            {
                *handle = gattXpanClient->handles.BearerPreferenceHandle;
            }
            break;
        case GATT_XPAN_CLIENT_MAC_ADDRESS:
            {
                *handle = gattXpanClient->handles.MacAddressHandle;
            }
            break;
        case GATT_XPAN_CLIENT_REQUESTED_SAP_POWER_STATE:
            {
                *handle = gattXpanClient->handles.RequestedSapPowerStateHandle;
            }
            break;
        case GATT_XPAN_CLIENT_SERVER_FEATURES:
            {
                *handle = gattXpanClient->handles.serverFeaturesHandle;
            }
            break;
        case GATT_XPAN_CLIENT_AUDIO_BEARER_SWITCH_RESPONSE:
            {
                *handle = gattXpanClient->handles.audioBearerSwitchResponseHandle;
            }
            break;
        case GATT_XPAN_CLIENT_NUM_DEVICES_PRESENT:
            {
                *handle = gattXpanClient->handles.numDevicesPresentHandle;
            }
            break;
        case GATT_XPAN_CLIENT_VOICE_BACK_CHANNEL_PERIODICITY:
            {
                *handle = gattXpanClient->handles.voiceBackChannelPeriodicityHandle;
            }
            break;
        case GATT_XPAN_CLIENT_REQUEST_WIFI_SCAN_RESULTS:
            {
                *handle = gattXpanClient->handles.requestWiFiScanResultsHandle;
            }
            break;
        case GATT_XPAN_CLIENT_ROAMING_REQUEST_RESPONSE:
            {
                *handle = gattXpanClient->handles.roamingRequestResponseHandle;
            }
            break;
        default:
            {
                handleInitialised = FALSE;
                GATT_XPAN_CLIENT_WARNING("Invalid XPAN Characteristic Id\n");
            }
            break;
        }
    }
    else
    {
        handleInitialised = FALSE;
    }

    return handleInitialised;
}

ServiceHandle getXpanServiceHandle(GXPANC **gatt_xpan_client, CsrCmnList_t *list)
{
    ServiceHandle newHandle = ServiceHandleNewInstance((void **)gatt_xpan_client, sizeof(GXPANC));

    if((*gatt_xpan_client))
    {
        ServiceHandleListElm_t *elem = XPAN_ADD_SERVICE_HANDLE(*list);

        elem->service_handle = newHandle;
        (*gatt_xpan_client)->srvcElem = elem;
    }

    return newHandle;
}
#endif /* EXCLUDE_GATT_XPAN_CLIENT_MODULE */